package org.wattdepot.cli;

import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.resource.source.jaxb.Source;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Scanner;

/**
 * A command line interface for accessing information on a simulated version
 * of Oahu's power plants.
 * @author Wing Cheung Ma, Edwin Lim
 */
public class CommandLineInterface {
  /** The URL to the public WattDepot Server. */
  protected String hostUri = "http://server.wattdepot.org:8182/wattdepot/";
  /** Holds an instance of the WattDepot client. */
  protected WattDepotClient client;
  /** Carriage return on this operating system. */
  protected String cr = System.getProperty("line.separator");
  /** Error statement for client problems. */  
  protected static final String clientError = "Client Problem";
  /** Error statement for xml problems. */  
  protected static final String xmlError = "Xml Problem";
  /** Error statement for authorization problems. */  
  protected static final String notAuthError = "You are not authorized";
  /** Error statement for input error. */  
  protected static final String inputError = "Input error";
  /** The source does not exist. */  
  protected static final String sourceNotFound = "The source inputted does not exist.";
  /** Timestamp exception.              */
  protected static final String timeProblem = "times stamp problem";
  
  /**
   * Connect to the service and execute some simple commands. Returns immediately if a connection to
   * the service could not be obtained.
   * 
   */
  public CommandLineInterface() {
    client = new WattDepotClient(this.hostUri);
    // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }

  }


  /**
   * The main program that is invoked from 'java -jar wattdepot-cli.jar'.
   * The parsing of the arguments and method is copied from Remy Baumgarten, and Kevin Chiogioji's
   * CommandLineInterface. Thanks.
   * @param args All args are ignored.
   * @throws Exception return an error message
   * 
   */
  public static void main(String[] args) throws Exception {
    
    //possible commands put into the map for different calls to command classes
    System.out.println("Starting CLI.");
    CommandLineInterface cli = new CommandLineInterface();
    cli.mainInterface();
    
   }
  
  /**
   * This is the interface that will run to take input and refer to the interface classes
   * to handle each command.
   */
  public void mainInterface() {
    Map<String, WattDepotCliCommand> commandMap = new HashMap<String, WattDepotCliCommand>();
    commandMap.put("sources", new ListSources());
    commandMap.put("summary", new ListSrcSummary());
    commandMap.put("sensordatatimestamp", new SensorData());
    commandMap.put("dailysensordataday", new SensorDataDay());
    commandMap.put("powerstatsday", new PowerGeneratedDay());
    commandMap.put("powertimestamp", new PowerGeneratedTimeStampCommand());
    commandMap.put("chartpower", new ChartCommand());
    commandMap.put("total", new ListTotal());
    commandMap.put("help", new HelpCommand());
    commandMap.put("fueltypes", new FuelTypes());
    commandMap.put("totalpower", new TotalPowerFuelType());
    commandMap.put("carboncontent", new CarbonContent());
    
    // Indicate successful connection.
    System.out.println("Connected to " + client.getWattDepotUri() + "\n");
    //input variables
    Scanner inputScan = new Scanner (System.in);
    String input = "";
    String command = null;
    String quitCom = "quit";

//    String output = "";
//    List<String> commandList = new ArrayList<String>();

    //main command prompt mechanism loop
    while (true) {
      System.out.print(">");
      input = inputScan.nextLine();
      //handling all 10 command options
      List<String> cList = deliminateCommand(input);
      command = cList.remove(0);
      //use string to find a match and execute that class for the doCommand
      WattDepotCliCommand commandInstance = commandMap.get(command);
      
      if (input.equalsIgnoreCase(quitCom)) {
        System.out.println("Quitting CLI...");
        System.exit(1);
      }

      else if (commandInstance == null) {
        System.out.println("More inputs please");
      }
      
      else {
        System.out.println(commandInstance.doCommand(cList));
      }
    }    
  }


  /**
   * Tokenizes the command(s) entered and puts them into an ArrayList.
   * First string is a clump of the string to match with commands.
   * 
   * This is a copied method from the CommandLineInterface of
   * Remy Baumgarten, and Kevin Chiogioji.
   * It has been modified since, to update to Version2.0 standards.
   * @param command String of commands entered by user.
   * @return ArrayList<String> delimited list of commands
   */
  public static List<String> deliminateCommand(String command) {
    StringTokenizer st = new StringTokenizer(command);
    List<String> commands = new ArrayList<String>();
    try {
      // Tokenize string and add to ArrayList
      while (st.hasMoreTokens()) {
        commands.add(st.nextToken());
      }
      // Check if first word of command is "list"

        // For each command remove keywords such as source, day, etc. so list only contains command
        // and parametersFailed to connect t
        if (commands.get(0).equalsIgnoreCase("summary")
            || commands.get(0).equalsIgnoreCase("sources")) {
          commands.add(0,(commands.remove(0)));
        }
        
        else if (commands.get(0).equalsIgnoreCase("sensordata") 
            && commands.get(2).equalsIgnoreCase("timestamp")) {
          commands.add(0, commands.remove(0).concat(commands.remove(1)));
        }
        
        else if  (commands.get(0).equalsIgnoreCase("dailysensordata") 
            && commands.get(2).equalsIgnoreCase("day")) {
          commands.add(0, commands.remove(0).concat(commands.remove(1)));
        }
        
        else if (commands.get(0).equalsIgnoreCase("power")
            && commands.get(3).equalsIgnoreCase("timestamp")) {
          commands.add(0, (commands.remove(0)).concat(commands.remove(2)));
        }
        
        else if (commands.get(0).equalsIgnoreCase("powerstats") && commands.get(3).equals("day")) {
          commands.add(0, (commands.remove(0)).concat(commands.remove(2)));
          commands.remove(4);
          commands.remove(5);
        }
        
        else if (commands.get(0).equalsIgnoreCase("total")) {
          commands.add(0, commands.remove(0));
          commands.remove(2);
          commands.remove(3);
          commands.remove(4);
        }

      // Check if command begins with "chart" and edit list so only the command and parameters
      // remain
        else if (commands.get(0).equalsIgnoreCase("chart")) {
        commands.add(0, commands.remove(0).concat(commands.remove(0)));
        commands.remove(5);
        commands.remove(6);
      }

    }
    catch (IndexOutOfBoundsException iobe) {
      commands.add("bad command");
      return commands;
    }
    return commands;
  }
  

  /**
   * Looks for a match in the available sources. The method is a check
   * to make sure the source exists.
   * @param inputSource a string from user
   * @return the source found or null
   * @throws WattDepotClientException If anything goes wrong.
   */
  public Source searchSource(String inputSource) throws WattDepotClientException {
    List<Source> sources = client.getSources();

    // Gets the power plants that are parents
    for (Source source : sources) {

      if ((source.getName()).equalsIgnoreCase(inputSource)) {
        return source;
      }

    }
    return null;
  }


}

